home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianVisContours.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  34KB  |  1,283 lines

  1. /*ScianVisContours.c
  2.   June 14, 1991
  3.   Eric Pepke
  4.   Routines for contour visualization object
  5.  
  6.   The contour object takes a scalar field defined over a data form with
  7.   topological dimension 2.  The spatial dimension of the dataset may be 
  8.   either 2 or 3.  If the spatial dimension is 2, the Z is assumed to be
  9.   zero.  The contour visualization object works for regular data forms,
  10.   and curvilinear data forms.
  11.  
  12. */
  13.  
  14. #include "Scian.h"
  15. #include "ScianTypes.h"
  16. #include "ScianArrays.h"
  17. #include "ScianWindows.h"
  18. #include "ScianTextBoxes.h"
  19. #include "ScianObjWindows.h"
  20. #include "ScianEvents.h"
  21. #include "ScianIcons.h"
  22. #include "ScianColors.h"
  23. #include "ScianControls.h"
  24. #include "ScianLists.h"
  25. #include "ScianSpaces.h"
  26. #include "ScianSliders.h"
  27. #include "ScianIDs.h"
  28. #include "ScianDatasets.h"
  29. #include "ScianErrors.h"
  30. #include "ScianVisObjects.h"
  31. #include "ScianVisContours.h"
  32. #include "ScianStyle.h"
  33. #include "ScianPictures.h"
  34. #include "ScianTitleBoxes.h"
  35. #include "ScianButtons.h"
  36. #include "ScianMethods.h"
  37. #include "ScianDraw.h"
  38. #include "ScianTemplates.h"
  39. #include "ScianTemplateHelper.h"
  40.  
  41. ObjPtr contourLineClass;        /*Contour line object*/
  42. ObjPtr contoursClass;
  43.  
  44. typedef struct xyzStruct
  45.     {
  46.     struct xyzStruct *next;        /*Pointer to next in list*/
  47.     real x, y, z;            /*Coordinates*/
  48.     real nx, ny, nz;        /*Normals*/
  49.     } XYZ;
  50.  
  51. #ifdef PROTO
  52. static Bool NextContour(ObjPtr, real *);
  53. unsigned char FindQuadJoinings(int initState[2][2]);
  54. void FollowContour(ObjPtr surface, unsigned char *joinings, 
  55.             long i, long j, long iSize, long jSize,
  56.             int startJoin, real contourValue, Bool reverse,
  57.             int lineWidth);
  58. XYZ *NewXYZNode(long i, long j, int dir, real contourValue);
  59. #else
  60. static Bool NextContour();
  61. unsigned char FindQuadJoinings();
  62. void FollowContour();
  63. XYZ *NewXYZNode();
  64. #endif
  65.  
  66.  
  67.  
  68. static ObjPtr ContoursInit(object)
  69. ObjPtr object;
  70. /*Initializes a contours object*/
  71. {
  72.     ObjPtr minMax;
  73.     real bounds[6];
  74.     real xySize, zSize;
  75.     ObjPtr contourField, mainDataset, colorObj, deformObj;
  76.     real min, max, *elements;
  77.     double ddiff, majorWidth;
  78.     int nTics;
  79.  
  80.     MakeVar(object, MAINDATASET);
  81.     SetVar(object, COLOROBJ, colorObj = GetVar(object, MAINDATASET));
  82.     if (colorObj)
  83.     {
  84.     SetVar(object, COLORS, ObjTrue);
  85.     }
  86.     SetVar(object, DEFORMOBJ, deformObj = GetVar(object, MAINDATASET));
  87.  
  88.     /*Heuristically determine whether to displace Z*/
  89.     GetBounds(object, bounds);
  90.     xySize = bounds[1] - bounds[0];
  91.     xySize = MAX(xySize, bounds[3] - bounds[2]);
  92.     xySize = MAX(xySize, bounds[5] - bounds[4]);
  93.     if (GetVar(colorObj, DATA))
  94.     {
  95.     MakeVar(deformObj, MINMAX);
  96.     minMax = GetVar(deformObj, MINMAX);
  97.     zSize = ((real *) ELEMENTS(minMax))[1] - ((real *) ELEMENTS(minMax))[0];
  98.     if (zSize < xySize * 0.5)
  99.     {
  100.         SetVar(object, DEFORMSWITCH, NewInt(1));
  101.     }
  102.     else
  103.     {
  104.         SetVar(object, DEFORMSWITCH, NewInt(0));
  105.     }
  106.     }
  107.  
  108.     /*Get the contour field*/
  109.     contourField = GetObjectVar("ContoursInit", object, MAINDATASET);
  110.     if (!contourField) return ObjFalse;
  111.     while (mainDataset = GetVar(contourField, MAINDATASET))
  112.     {
  113.     contourField = mainDataset;
  114.     }
  115.  
  116.     /*Find its min and max*/
  117.     MakeVar(contourField, MINMAX);
  118.     minMax = GetVar(contourField, MINMAX);
  119.     if (minMax)
  120.     {
  121.     elements = ELEMENTS(minMax);
  122.     min = elements[0];
  123.     max = elements[1];
  124.     }
  125.     else
  126.     {
  127.     min = 0.0;
  128.     max = 1.0;
  129.     }
  130.  
  131.     ddiff = max - min;
  132.     CalcGoodSteps(ddiff, 50, 10, &majorWidth, &nTics);
  133.  
  134.     SetVar(object, CONTOURCENTER, NewReal(0.0));
  135.     SetVar(object, CONTOURSTEP, NewReal(majorWidth));
  136.     SetVar(object, CONTOURMAX, NewReal(PLUSINF));
  137.     SetVar(object, CONTOURDIV, NewInt(MAX(1, nTics)));
  138.     SetVar(object, CONTOURMIN, NewReal(MINUSINF));
  139.  
  140.     return ObjTrue;
  141. }
  142.  
  143. static ObjPtr SetContoursMainDataset(visObj, dataSet)
  144. ObjPtr visObj, dataSet;
  145. /*Sets the main data set of visObj to dataSet*/
  146. {
  147.     SetVar(visObj, MAINDATASET, dataSet);
  148.     return ObjTrue;
  149. }
  150.  
  151. static ObjPtr MakeContoursColored(visObject)
  152. ObjPtr visObject;
  153. /*Makes the contours colored*/
  154. {
  155.     SetVar(visObject, PICCOLORED, ObjTrue);
  156.     if (GetPredicate(visObject, COLORS))
  157.     {
  158.     ObjPtr contourField, contourForm;
  159.     ObjPtr colorField, colorForm;
  160.     ObjPtr var;
  161.     ObjPtr surface;
  162.     ObjPtr palette;
  163.  
  164.     /*Get the contour field and its form*/
  165.     contourField = GetObjectVar("MakeContoursColored", visObject, MAINDATASET);
  166.     if (!contourField) return ObjFalse;
  167.     contourForm = GetObjectVar("MakeContoursColored", contourField, DATAFORM);
  168.     if (!contourForm) return ObjFalse;
  169.  
  170.     /*Get the color field and its form*/
  171.     colorField = GetObjectVar("MakeContoursColored", visObject, COLOROBJ);
  172.     if (!colorField) return ObjFalse;
  173.     colorForm = GetObjectVar("MakeContoursColored", colorField, DATAFORM);
  174.     if (!colorForm) return ObjFalse;
  175.  
  176.     /*Get the color palette*/
  177.     MakeVar(colorField, CPALETTE);
  178.     palette = GetPaletteVar("MakeContoursColored", colorField, CPALETTE);
  179.     if (!palette)
  180.     {
  181.         return ObjFalse;
  182.     }
  183.     SetPalette(palette);
  184.  
  185.     /*Get the surface to color*/
  186.     surface = GetPictureVar("MakeContoursColored", visObject, SURFACE);
  187.     if (!surface) return ObjFalse;
  188.  
  189.     /*Have to make it colored by the object.*/
  190.     ColorPictureByObject(surface, colorField, GetPredicate(visObject, INTERPCOLORS));
  191.     }
  192.     return ObjTrue;
  193. }
  194.  
  195. #ifdef PROTO
  196. static Bool NextContour(ObjPtr contourList, real *contourValue)
  197. #else
  198. static Bool NextContour(contourList, contourValue)
  199. ObjPtr contourList;
  200. real *contourValue;
  201. #endif
  202. /*Stuffs the next contour ABOVE contourValue in contourList into contourValue
  203. */
  204. {
  205.     ObjPtr var;
  206.     real test, closest;
  207.     Bool closestSet = false;
  208.     ThingListPtr runner;
  209.  
  210.     runner = LISTOF(contourList);
  211.     while (runner)
  212.     {
  213.     var = GetRealVar("NextContour", runner -> thing, STARTVALUE);
  214.     if (var)
  215.     {
  216.         test = GetReal(var);
  217.         if (test > *contourValue)
  218.         {
  219.         if (!closestSet || test < closest)
  220.         {
  221.             /*Found the next one*/
  222.             closestSet = true;
  223.             closest = test;
  224.         }
  225.         }
  226.     }
  227.     runner = runner -> next;
  228.     }
  229.  
  230.     if (closestSet)
  231.     {
  232.     *contourValue = closest;
  233.     }
  234.     return closestSet;
  235. }
  236.  
  237. /*Quadrilateral for contouring is numbered like this
  238.  
  239.   2       3
  240.    +-----+
  241.    |  2  |
  242. j  |3   1|
  243.    |  0  |
  244.    +-----+
  245.   0       1
  246.       i
  247. */
  248.  
  249. unsigned char fixedJoinings[] =
  250.     {
  251.         0x00,    /* 0000 */
  252.         0x30,    /* 0001 */
  253.         0x10,    /* 0010 */
  254.         0x70,    /* 0011 */
  255.         0x0B,    /* 0100 */
  256.         0x20,    /* 0101 */
  257.         0x1B,    /* 0110 */
  258.         0x60,    /* 0111 */
  259.         0x60,    /* 1000 */
  260.         0x36,    /* 1001 */
  261.         0x20,    /* 1010 */
  262.         0x0B,    /* 1011 */
  263.         0x70,    /* 1100 */
  264.         0x10,    /* 1101 */
  265.         0x30,    /* 1110 */
  266.         0x00    /* 1111 */
  267.     };
  268. unsigned char joinChars[] =
  269.     {
  270.         ' ',    /* 0000 */
  271.         '\\',    /* 0001 */
  272.         '/',    /* 0010 */
  273.         '-',    /* 0011 */
  274.         '/',    /* 0100 */
  275.         '|',    /* 0101 */
  276.         '/',    /* 0110 */
  277.         '\\',    /* 0111 */
  278.         '\\',    /* 1000 */
  279.         '\\',    /* 1001 */
  280.         '|',    /* 1010 */
  281.         '/',    /* 1011 */
  282.         '-',    /* 1100 */
  283.         '/',    /* 1101 */
  284.         '\\',    /* 1110 */
  285.         ' '        /* 1111 */
  286.     };
  287.  
  288. #ifdef PROTO
  289. unsigned char FindQuadJoinings(int initState[2][2])
  290. #else
  291. unsigned char FindJoinings(initState)
  292. int initState[2][2];
  293. #endif
  294. /*Finds the joinings for initial state initState*/
  295. {
  296.     int index;
  297.  
  298.     index = initState[0][0] +
  299.         (initState[1][0] << 1) +
  300.         (initState[0][1] << 2) +
  301.         (initState[1][1] << 3);
  302.  
  303.     return fixedJoinings[index];
  304. }
  305.  
  306. #define SELJOIN(j, n) (((n) ? ((j) >> 4) : (j)) & 0xF)
  307. #define WIPEJOIN(j, n) ((n) ? ((j) &= 0xF) : ((j) &= 0xF0))
  308. #define SELEND(j, n) (((n) ? ((j) >> 2) : (j)) & 0x3)
  309.  
  310. #ifdef PROTO
  311. XYZ *NewXYZNode(long i, long j, int dir, real contourValue)
  312. #else
  313. XYZ *NewXYZNode(i, j, dir, contourValue)
  314. long i, y;
  315. int dir;
  316. real contourValue;
  317. #endif
  318. /*Returns a new XYZ node for dir from i, j assuming contourValue.
  319.   Expects dataset in FIELD1 and data form in FIELD2.*/
  320. {
  321.     XYZ *node;
  322.     long iPlus, jPlus;
  323.     real x1, y1, z1, f1, x2, y2, z2, f2, w1, w2;
  324.     long curDim[2];
  325.     int nComponents;
  326.     real c[2][2][3];        /*Corner position*/
  327.     real cf[2][2];        /*Corner function*/
  328.     real v1[3], v2[3];        /*Vectors*/
  329.     real x[3];            /*Cross product*/
  330.  
  331.     /*Make the node*/
  332.     node = (XYZ *) Alloc(sizeof(XYZ));
  333.     node -> next = NULL;
  334.  
  335.     /*Get the components in the data field*/
  336.     nComponents = GetNComponents(FIELD2);
  337.  
  338.     /*Fill the corners*/
  339.     for (iPlus = 0; iPlus < 2; ++iPlus)
  340.     {
  341.     for (jPlus = 0; jPlus < 2; ++jPlus)
  342.     {
  343.         curDim[0] = i + iPlus;
  344.         curDim[1] = j + jPlus;
  345.         c[iPlus][jPlus][0] = SelectFieldComponent(FIELD2, 0, curDim);
  346.         c[iPlus][jPlus][1] = SelectFieldComponent(FIELD2, 1, curDim);
  347.         c[iPlus][jPlus][2] = nComponents >= 3 ?                        
  348.             SelectFieldComponent(FIELD2, 2, curDim) : 0.0;
  349.         cf[iPlus][jPlus] = SelectFieldScalar(FIELD1, curDim);    
  350.     }
  351.     }
  352.  
  353.     /*First endpoint*/                            
  354.     switch(dir)                                
  355.     {                                    
  356.     case 0:                                
  357.         /*Do 0, 0*/                            
  358.         iPlus = 0;                        
  359.         jPlus = 0;                        
  360.         break;                            
  361.     case 1:                                
  362.         /*Do 1, 0*/                            
  363.         iPlus = 1;                    
  364.         jPlus = 0;                        
  365.         break;                            
  366.     case 2:                                
  367.         /*Do 1, 1*/                            
  368.         iPlus = 1;                    
  369.         jPlus = 1;                    
  370.         break;                            
  371.     case 3:                                
  372.         /*Do 0, 1*/                            
  373.         iPlus = 0;                        
  374.         jPlus = 1;                    
  375.         break;                            
  376.     }                                    
  377.     x1 = c[iPlus][jPlus][0];            
  378.     y1 = c[iPlus][jPlus][1];            
  379.     z1 = c[iPlus][jPlus][2];            
  380.     f1 = cf[iPlus][jPlus];            
  381.                                     
  382.     /*Second endpoint*/                            
  383.     switch(dir)                                
  384.     {                                    
  385.     case 0:                                
  386.         /*Do 1, 0*/                            
  387.         iPlus = 1;                    
  388.         jPlus = 0;                        
  389.         break;                            
  390.     case 1:                                
  391.         /*Do 1, 1*/                            
  392.         iPlus = 1;                    
  393.         jPlus = 1;                    
  394.         break;                            
  395.     case 2:                                
  396.         /*Do 0, 1*/                            
  397.         iPlus = 0;                        
  398.         jPlus = 1;                    
  399.         break;                            
  400.     case 3:                                
  401.         /*Do 0, 0*/                            
  402.         iPlus = 0;                        
  403.         jPlus = 0;                        
  404.         break;                            
  405.     }                                    
  406.     x2 = c[iPlus][jPlus][0];            
  407.     y2 = c[iPlus][jPlus][1];            
  408.     z2 = c[iPlus][jPlus][2];            
  409.     f2 = cf[iPlus][jPlus];            
  410.                                                                         
  411.     /*Now interpolate*/
  412.     if ((f1 <= contourValue) && (contourValue <= f2))
  413.     {
  414.     real rDiff = 1.0 / (f2 - f1);
  415.     w1 = (f2 - contourValue) * rDiff;
  416.     w2 = (contourValue - f1) * rDiff;
  417.     }
  418.     else if ((f2 <= contourValue) && (contourValue <= f1))
  419.     {
  420.     real rDiff = 1.0 / (f1 - f2);
  421.     w2 = (f1 - contourValue) * rDiff;
  422.     w1 = (contourValue - f2) * rDiff;
  423.     }
  424.     else
  425.     {
  426.     w1 = w2 = 0.0;
  427.     fprintf(stderr, "Contour error at (%d %d)\n", i, j);
  428.     }
  429.  
  430.     node -> x = x1 * w1 + x2 * w2;
  431.     node -> y = y1 * w1 + y2 * w2;
  432.     node -> z = z1 * w1 + z2 * w2;
  433.  
  434.     /*Now find the normals*/
  435.     v1[0] = c[0][1][0] - c[0][0][0];
  436.     v1[1] = c[0][1][1] - c[0][0][1];
  437.     v1[2] = c[0][1][2] - c[0][0][2];
  438.  
  439.     v2[0] = c[1][0][0] - c[0][0][0];
  440.     v2[1] = c[1][0][1] - c[0][0][1];
  441.     v2[2] = c[1][0][2] - c[0][0][2];
  442.  
  443.     CROSS(v1, v2, x);
  444.     NORMALIZE(x);
  445.     node -> nx = x[0];
  446.     node -> ny = x[1];
  447.     node -> nz = x[2];
  448.  
  449.     return node;
  450. }
  451.  
  452.  
  453. #ifdef PROTO
  454. void FollowContour(ObjPtr surface, unsigned char *joinings, 
  455.             long i, long j, long iSize, long jSize,
  456.             int startJoin,
  457.             real contourValue, Bool reverse, int lineWidth)
  458. #else
  459. void FollowContour(surface, joinings, i, j, iSize, jSize, startJoin, 
  460.     contourValue, reverse, lineWidth)
  461. ObjPtr surface;
  462. unsigned char *joinings; 
  463. long i; 
  464. long j; 
  465. long iSize; 
  466. long jSize;
  467. int startJoin;
  468. real contourValue;
  469. Bool reverse;
  470. int lineWidth;
  471. #endif
  472. /*Follows a contour within surface using joinings starting at startJoin at i, j.
  473. startJoin is 0 for LSN and 1 for MSN;
  474. iSize and jSize gives the size of the array.  Dataset is assumed to be in
  475. FIELD1 and dataform in FIELD2.  This routine runs contours both ways.
  476. Side effects: removes runs from joinings.  If reverse is true, reverses the
  477. sense of the normal*/
  478. {
  479.     unsigned int joining, a, b, iCur, jCur, aCur, bCur, match, curJoin;
  480.     long count, k;
  481.     XYZ *first, *last, *runner;
  482.     long curDim[2];
  483.     VertexPtr vertices;
  484.     Bool firstTime;
  485.  
  486.     /*Set joining to the joining to start*/
  487.     joining = SELJOIN(joinings[i + j * iSize], startJoin);
  488.  
  489.     /*Set a and b to the two ends of the joining*/
  490.     a = SELEND(joining, 1);
  491.     b = SELEND(joining, 0);
  492.  
  493.     /*Return if null*/
  494.     if (a == b) return;
  495.  
  496.     /*Want to go from a to b.  Reverse if neccessary.*/
  497.     if ((i == 0 && b == 3) ||        /*Off left side*/
  498.     (i == iSize - 2 && b == 1) ||    /*Off right side*/
  499.     (j == 0 && b == 0) ||        /*Off bottom side*/
  500.     (j == jSize - 2 && b == 2))    /*Off top side*/ 
  501.     {
  502.     int t;
  503.     t = a;
  504.     a = b;
  505.     b = t;
  506.     }
  507.  
  508.     /*Make the first XYZ in the contour line*/
  509.     first = last = NewXYZNode(i, j, a, contourValue);
  510.     last -> next = NULL;
  511.  
  512.     iCur = i;
  513.     jCur = j;
  514.     aCur = a;
  515.     bCur = b;
  516.     curJoin = startJoin;
  517.     /*Now run the contour, from aCur to bCur within iCur, jCur*/
  518.     for(;;)
  519.     {
  520.     /*Emit this joining onto the list*/
  521.     last -> next = NewXYZNode(iCur, jCur, bCur, contourValue);
  522.     last = last -> next;
  523.  
  524.     /*Delete this joining*/
  525.     WIPEJOIN(joinings[iCur + jCur * iSize], curJoin);
  526.  
  527.     /*Find a next place to go*/
  528.     switch(bCur)
  529.     {
  530.         case 0:
  531.         --jCur;
  532.         match = 2;
  533.         break;
  534.         case 1:
  535.         ++iCur;
  536.         match = 3;
  537.         break;
  538.         case 2:
  539.         ++jCur;
  540.         match = 0;
  541.         break;
  542.         case 3:
  543.         --iCur;
  544.         match = 1;
  545.         break;
  546.     }
  547.  
  548.     if (iCur < 0 || jCur < 0 || iCur >= iSize - 1 || jCur >= jSize - 1)
  549.     {
  550.         /*Fallen off the edge*/
  551.         break;
  552.     }
  553.  
  554.     /*Get the new joining and see if it matches up.  Try 0 first.*/
  555.     joining = SELJOIN(joinings[iCur + jCur * iSize], 0);
  556.     if (joining)
  557.     {
  558.         if (SELEND(joining, 1) == match)
  559.         {
  560.         aCur = SELEND(joining, 1);
  561.         bCur = SELEND(joining, 0);
  562.         curJoin = 0;
  563.         continue;
  564.         }
  565.         if (SELEND(joining, 0) == match)
  566.         {
  567.         aCur = SELEND(joining, 0);
  568.         bCur = SELEND(joining, 1);
  569.         curJoin = 0;
  570.         continue;
  571.         }
  572.     }
  573.  
  574.     /*OK, so now try one*/
  575.     joining = SELJOIN(joinings[iCur + jCur * iSize], 1);
  576.     if (joining)
  577.     {
  578.         if (SELEND(joining, 1) == match)
  579.         {
  580.         aCur = SELEND(joining, 1);
  581.         bCur = SELEND(joining, 0);
  582.         curJoin = 1;
  583.         continue;
  584.         }
  585.         if (SELEND(joining, 0) == match)
  586.         {
  587.         aCur = SELEND(joining, 0);
  588.         bCur = SELEND(joining, 1);
  589.         curJoin = 1;
  590.         continue;
  591.         }
  592.     }
  593.  
  594.     break;
  595.     }
  596.  
  597.     /*Follow the contour backward from the beginning, just in case*/
  598.     iCur = i;
  599.     jCur = j;
  600.     bCur = a;
  601.     curJoin = startJoin;
  602.     firstTime = true;
  603.     /*Now run the contour, from aCur to bCur within iCur, jCur*/
  604.     for(;;)
  605.     {
  606.     if (firstTime)
  607.     {
  608.         firstTime = false;
  609.     }
  610.     else
  611.     {
  612.         XYZ *temp;
  613.         /*Emit this joining onto the list*/
  614.         temp = NewXYZNode(iCur, jCur, bCur, contourValue);
  615.         temp -> next = first;
  616.         first = temp;
  617.     }
  618.  
  619.     /*Delete this joining*/
  620.     WIPEJOIN(joinings[iCur + jCur * iSize], curJoin);
  621.  
  622.     /*Find a next place to go*/
  623.     switch(bCur)
  624.     {
  625.         case 0:
  626.         --jCur;
  627.         match = 2;
  628.         break;
  629.         case 1:
  630.         ++iCur;
  631.         match = 3;
  632.         break;
  633.         case 2:
  634.         ++jCur;
  635.         match = 0;
  636.         break;
  637.         case 3:
  638.         --iCur;
  639.         match = 1;
  640.         break;
  641.     }
  642.  
  643.     if (iCur < 0 || jCur < 0 || iCur >= iSize - 1 || jCur >= jSize - 1)
  644.     {
  645.         /*Fallen off the edge*/
  646.         break;
  647.     }
  648.  
  649.     /*Get the new joining and see if it matches up.  Try 0 first.*/
  650.     joining = SELJOIN(joinings[iCur + jCur * iSize], 0);
  651.     if (joining)
  652.     {
  653.         if (SELEND(joining, 1) == match)
  654.         {
  655.         aCur = SELEND(joining, 1);
  656.         bCur = SELEND(joining, 0);
  657.         curJoin = 0;
  658.         continue;
  659.         }
  660.         if (SELEND(joining, 0) == match)
  661.         {
  662.         aCur = SELEND(joining, 0);
  663.         bCur = SELEND(joining, 1);
  664.         curJoin = 0;
  665.         continue;
  666.         }
  667.     }
  668.  
  669.     /*OK, so now try one*/
  670.     joining = SELJOIN(joinings[iCur + jCur * iSize], 1);
  671.     if (joining)
  672.     {
  673.         if (SELEND(joining, 1) == match)
  674.         {
  675.         aCur = SELEND(joining, 1);
  676.         bCur = SELEND(joining, 0);
  677.         curJoin = 1;
  678.         continue;
  679.         }
  680.         if (SELEND(joining, 0) == match)
  681.         {
  682.         aCur = SELEND(joining, 0);
  683.         bCur = SELEND(joining, 1);
  684.         curJoin = 1;
  685.         continue;
  686.         }
  687.     }
  688.     break;
  689.     }
  690.  
  691.     /*Count the elements in the list*/
  692.     runner = first;
  693.     count = 0;
  694.     while (runner)
  695.     {
  696.     ++count;
  697.     runner = runner -> next;
  698.     }
  699.  
  700.     /*Make the vertices*/
  701.     vertices = (VertexPtr) Alloc(count * sizeof(Vertex));
  702.     if (vertices)
  703.     {
  704.     /*Run through the list, putting it on the vertices*/
  705.     runner = first;
  706.     for (k = 0; k < count; ++k)
  707.     {
  708.         vertices[k] . position[0] = runner -> x;
  709.         vertices[k] . position[1] = runner -> y;
  710.         vertices[k] . position[2] = runner -> z;
  711.         if (reverse)
  712.         {
  713.         vertices[k] . normal[0] = -runner -> nx;
  714.         vertices[k] . normal[1] = -runner -> ny;
  715.         vertices[k] . normal[2] = -runner -> nz;
  716.         }
  717.         else
  718.         {
  719.         vertices[k] . normal[0] = runner -> nx;
  720.         vertices[k] . normal[1] = runner -> ny;
  721.         vertices[k] . normal[2] = runner -> nz;
  722.         }
  723.         vertices[k] . colorIndex = 0;
  724.         runner = runner -> next;
  725.     }
  726.  
  727.     /*Make a contour line*/
  728.     AppendPolylineToPicture(surface, lineWidth, 2, count, vertices);
  729.  
  730.     /*Free the vertices*/
  731.     Free(vertices);
  732.     }
  733.  
  734.     /*Eliminate the XYZ list*/
  735.     while (first)
  736.     {
  737.     last = first -> next;
  738.     Free(first);
  739.     first = last;
  740.     }
  741. }
  742.  
  743. static ObjPtr MakeContoursSurface(visObject)
  744. ObjPtr visObject;
  745. /*Makes the surface in a contours object.  Also colors it.*/
  746. {
  747.     ObjPtr dataset;        /*The dataset the vis object represents*/
  748.     long datasetFlags;        /*Flags of the dataset*/
  749.     ObjPtr var;            /*Random variable*/
  750.     ObjPtr picture;        /*The picture to be made*/
  751.  
  752.     dataset = GetObjectVar("MakeContoursSurface", visObject, MAINDATASET);
  753.     if (!dataset)
  754.     {
  755.     return ObjFalse;
  756.     }
  757.  
  758.     datasetFlags = GetDatasetInfo(dataset);
  759.  
  760.     if (0 == datasetFlags & DS_HASFORM)
  761.     {
  762.     ReportError("MakeContoursSurface", "No data form");
  763.     return ObjFalse;
  764.     }
  765.  
  766.  
  767.     /*Make the new picture*/
  768.     picture = NewPicture();
  769.     if (!picture) return ObjFalse;
  770.  
  771.     if (datasetFlags & DS_UNSTRUCTURED)
  772.     {
  773.     return ObjFalse;
  774.     }
  775.     else
  776.     {
  777.     /*It's a structured dataset.*/
  778.     int topDim, nComponents;
  779.     long curDim[2], iDims[2];
  780.     ObjPtr dims;
  781.     RectMeshPtr rectMesh;
  782.     real temp[3];
  783.     int iDim, jDim;
  784.     Bool reverse;
  785.  
  786.     /*It must have dimension 2*/
  787.     topDim = GetTopDim(dataset);
  788.     if (topDim != 2)
  789.     {
  790.         ReportError("MakeContoursSurface", "Topological dimension must be 2.");
  791.         return ObjFalse;
  792.     }
  793.  
  794.     /*Get the actual topological dimensions*/
  795.     dims = GetDatasetFormDims(dataset);
  796.     if (!dims || !IsRealArray(dims) || RANK(dims) != 1 || DIMS(dims)[0] != 2)
  797.     {
  798.         ReportError("MakeContoursSurface", "No topological dimensions");
  799.         return ObjFalse;
  800.     }
  801.  
  802.     iDims[0] = ((real *) ELEMENTS(dims))[0];
  803.     iDims[1] = ((real *) ELEMENTS(dims))[1];
  804.  
  805.     /*Register the dataset and its dataform*/
  806.     if (!SetCurField(FIELD1, dataset))
  807.     {
  808.         return ObjFalse;
  809.     }
  810.     if (!SetCurForm(FIELD2, dataset))
  811.     {
  812.         return ObjFalse;
  813.     }
  814.     
  815.     reverse = GetPredicate(visObject, REVERSESENSE) ^
  816.           GetPredicate(dataset, ISLEFTHANDED);
  817.     if (reverse)
  818.     {
  819.         iDim = 1;
  820.         jDim = 0;
  821.     }
  822.     else
  823.     {
  824.         iDim = 0;
  825.         jDim = 1;
  826.     }
  827.  
  828.     var = GetVar(visObject, CONTOURCENTER);
  829.     if (var)
  830.     {
  831.         /*Create all the contour lines*/
  832.         ObjPtr minMax;
  833.         real *elements;
  834.         ThingListPtr runner;
  835.         double min, max, mid;
  836.         double curContour;
  837.         unsigned char *joinings;
  838.         long i, j, k, iPlus, jPlus;
  839.         int initState[2][2];
  840.         double test;
  841.         double center;        /*Center of contour*/
  842.         double step;        /*Plus and minus step*/
  843.         int nDivisions;        /*Number of divisions*/
  844.         double contourMin, contourMax;/*Min and max of contours*/
  845.         long contourIndex;
  846.  
  847.         center = GetReal(var);
  848.  
  849.         /*Get the step*/
  850.         var = GetRealVar("MakeContoursSurface", visObject, CONTOURSTEP);
  851.         if (!var)
  852.         {
  853.         return ObjFalse;
  854.         }
  855.         step = GetReal(var);
  856.         var = GetIntVar("MakeContoursSurface", visObject, CONTOURDIV);
  857.         if (!var)
  858.         {
  859.         return ObjFalse;
  860.         }
  861.         nDivisions = GetInt(var);
  862.         if (nDivisions > 0)
  863.         {
  864.             step /= nDivisions;
  865.         }
  866.         else
  867.         {
  868.         nDivisions = 1;
  869.         }
  870.  
  871.         /*Now the min and max*/
  872.         var = GetRealVar("MakeContoursSurface", visObject, CONTOURMAX);
  873.         if (!var)
  874.         {
  875.         return ObjFalse;
  876.         }
  877.         contourMax = GetReal(var);
  878.         var = GetRealVar("MakeContoursSurface", visObject, CONTOURMIN);
  879.         if (!var)
  880.         {
  881.         return ObjFalse;
  882.         }
  883.         contourMin = GetReal(var);
  884.  
  885.         /*Get the min and max of the dataset*/
  886.         MakeVar(dataset, MINMAX);
  887.         minMax = GetVar(dataset, MINMAX);
  888.         if (minMax)
  889.         {
  890.         elements = ELEMENTS(minMax);
  891.         min = elements[0];
  892.          max = elements[1];
  893.         }
  894.         else
  895.         {
  896.         min = 0.0;
  897.         max = 1.0;
  898.         }
  899.         mid = (min + max) * 0.5;
  900.  
  901.         /*Make the joinings array*/
  902.         joinings = (unsigned char *) Alloc(iDims[0] * iDims[1]);
  903.         for (k = 0; k < iDims[0] * iDims[1]; ++k)
  904.         {
  905.         joinings[k] = 0;
  906.         }
  907.  
  908.         /*Clip min and max with contour min and max*/
  909.         min = MAX(min, contourMin);
  910.         max = MIN(max, contourMax);
  911.  
  912.         /*Find the index of the first contour*/
  913.         contourIndex = (min - center) / ABS(step);
  914.         curContour = center + contourIndex * ABS(step);
  915.  
  916.         /*Go through the contours, finding joinings*/        
  917.         while (curContour <= max)
  918.         {
  919.         /*Generate joinings for this contour*/
  920.         for (j = 0; j < iDims[jDim] - 1; ++j)
  921.         {
  922.             for (i = 0; i < iDims[iDim] - 1; ++i)
  923.             {
  924.             /*Set up initState*/
  925.             for (jPlus = 0; jPlus < 2; ++jPlus)
  926.             {
  927.                 for (iPlus = 0; iPlus < 2; ++iPlus)
  928.                 {
  929.                 curDim[iDim] = i + iPlus;
  930.                 curDim[jDim] = j + jPlus;
  931.                 test = SelectFieldScalar(FIELD1, curDim);
  932.                 if (test == missingData)
  933.                 {
  934.                     goto cellMissing;
  935.                 }
  936.                 initState[(iDim == 0) ? iPlus : jPlus]
  937.                      [(jDim == 1) ? jPlus : iPlus] =
  938.                     (curContour > mid) ?
  939.                     (test <= curContour ? 1 : 0) :
  940.                     (test <= curContour ? 0 : 1);
  941.                 }
  942.             }
  943.             curDim[iDim] = i;
  944.             curDim[jDim] = j;
  945.             joinings[curDim[1] * iDims[0] + curDim[0]] =
  946.                 FindQuadJoinings(initState);
  947. cellMissing:;
  948.             }
  949.         }
  950.  
  951.         /*Follow all the contours*/
  952.         for (j = 0; j < iDims[jDim] - 1; ++j)
  953.         {
  954.             for (i = 0; i < iDims[iDim] - 1; ++i)
  955.             {
  956.             int joining;
  957.             curDim[iDim] = i;
  958.             curDim[jDim] = j;
  959.             /*Must have a joining involving the bottom edge*/
  960.             joining = joinings[curDim[1] * iDims[0] + curDim[0]];
  961.             if (joining & 0xF0)
  962.             {
  963.                 FollowContour(picture, joinings, curDim[0], curDim[1], iDims[0], iDims[1], 1, curContour, reverse ? false : true, 0);
  964.             }
  965.             joining = joinings[curDim[1] * iDims[0] + curDim[0]];
  966.             if (joining & 0x0F)
  967.             {
  968.                 FollowContour(picture, joinings, curDim[0], curDim[1], iDims[0], iDims[1], 0, curContour, reverse ? false : true, 0);
  969.             }
  970.             }  
  971.         }
  972.  
  973.         /*Next contour*/
  974.         ++contourIndex;
  975.         curContour = center + contourIndex * ABS(step);
  976.         }
  977.  
  978.         Free(joinings);
  979.     }
  980.     }
  981.  
  982.     SetVar(visObject, SURFACE, picture);
  983.     SetVar(picture, REPOBJ, visObject);
  984.     return ObjTrue;
  985. }
  986.  
  987. static ObjPtr AddContourControls(contour, panelContents)
  988. ObjPtr contour, panelContents;
  989. /*Adds controls appropriate to a contour object to panelContents*/
  990. {
  991.     ObjPtr titleBox, button, radio, var, corral, icon, name, contourField, mainDataset;
  992.     ObjPtr textBox, defaultIcon;
  993.     int width, left, top, bottom, right, mid;
  994.     ObjPtr control;
  995.     ObjPtr minMax;
  996.     char number[50];
  997.     real step, origin, min, max;
  998.     int divisions;
  999.  
  1000.     width = CWINWIDTH - 2 * CORRALBORDER - CWINCORRALWIDTH;
  1001.  
  1002.     /*Get the contour field*/
  1003.     contourField = GetObjectVar("AddContourControls", contour, MAINDATASET);
  1004.     if (!contourField) return ObjFalse;
  1005.     while (mainDataset = GetVar(contourField, MAINDATASET))
  1006.     {
  1007.     contourField = mainDataset;
  1008.     }
  1009.  
  1010.     /*Put in the contour corral at the top left*/
  1011.     left = MAJORBORDER;
  1012.     top = MAJORBORDER;
  1013.     corral = NewIconCorral(NULLOBJ,
  1014.                left, left + ONECORRALWIDTH,
  1015.                CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT,
  1016.                CWINHEIGHT - MAJORBORDER, 0);
  1017.     SetVar(corral, SINGLECORRAL, ObjTrue);
  1018.     SetVar(corral, TOPDOWN, ObjTrue);
  1019.     SetVar(corral, NAME, NewString("Contour Field"));
  1020.     SetVar(corral, HELPSTRING,
  1021.     NewString("This corral shows the dataset that is being used to make \
  1022. the contour display.  The locations of contours and color cells are calculated \
  1023. using this field.  The color of color cells is calculated using the Color Field, \
  1024. available in the Color control set."));
  1025.     PrefixList(panelContents, corral);
  1026.     SetVar(corral, PARENT, panelContents);
  1027.     SetVar(corral, REPOBJ, contour);
  1028.     SetMethod(corral, DROPINCONTENTS, DropInMainDatasetCorral);
  1029.  
  1030.     /*Create the contour source text box*/
  1031.     textBox = NewTextBox(left, left + ONECORRALWIDTH, 
  1032.              CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT - TEXTBOXSEP - TEXTBOXHEIGHT,
  1033.              CWINHEIGHT - MAJORBORDER - ONECORRALHEIGHT - TEXTBOXSEP,
  1034.              0, "Contour Field Text", "Contour Field");
  1035.     PrefixList(panelContents, textBox);
  1036.     SetVar(textBox, PARENT, panelContents);
  1037.     SetTextAlign(textBox, CENTERALIGN);
  1038.  
  1039.     top = CWINHEIGHT - 2 * MAJORBORDER - ONECORRALHEIGHT - TEXTBOXSEP - TEXTBOXHEIGHT;
  1040.  
  1041.     /*Put in an icon that represents the field*/
  1042.     name = GetVar(contourField, NAME);
  1043.     defaultIcon = GetVar(contourField, DEFAULTICON);
  1044.     if (defaultIcon)
  1045.     {
  1046.     icon = NewObject(defaultIcon, 0);
  1047.     SetVar(icon, NAME, name);
  1048.     }
  1049.     else
  1050.     {
  1051.     icon = NewIcon(0, 0, ICONQUESTION, GetString(name));
  1052.     }
  1053.     SetVar(icon, ICONLOC, NULLOBJ);
  1054.     SetVar(icon, REPOBJ, contourField);
  1055.     DropIconInCorral(corral, icon);
  1056.  
  1057.     var = GetRealVar("AddContourControls", contour, CONTOURSTEP);
  1058.     if (var)
  1059.     {
  1060.     step = GetReal(var);
  1061.     }
  1062.     else
  1063.     {
  1064.     SetVar(contour, CONTOURSTEP, NewReal(1.0));
  1065.     step = 1.0;
  1066.     }
  1067.  
  1068.     var = GetRealVar("AddContourControls", contour, CONTOURCENTER);
  1069.     if (var)
  1070.     {
  1071.     origin = GetReal(var);
  1072.     }
  1073.     else
  1074.     {
  1075.     SetVar(contour, CONTOURCENTER, NewReal(0.0));
  1076.     origin = 0.0;
  1077.     }
  1078.  
  1079.     var = GetRealVar("AddContourControls", contour, CONTOURMIN);
  1080.     if (var)
  1081.     {
  1082.     min = GetReal(var);
  1083.     }
  1084.     else
  1085.     {
  1086.     SetVar(contour, CONTOURMIN, NewReal(minusInf));
  1087.     min = minusInf;
  1088.     }
  1089.  
  1090.     var = GetRealVar("AddContourControls", contour, CONTOURMAX);
  1091.     if (var)
  1092.     {
  1093.     max = GetReal(var);
  1094.     }
  1095.     else
  1096.     {
  1097.     SetVar(contour, CONTOURMAX, NewReal(plusInf));
  1098.     max = plusInf;
  1099.     }
  1100.  
  1101.     var = GetIntVar("AddContourControls", contour, CONTOURDIV);
  1102.     if (var)
  1103.     {
  1104.     divisions = GetInt(var);
  1105.     }
  1106.     else
  1107.     {
  1108.     SetVar(contour, CONTOURDIV, NewInt(1));
  1109.     divisions = 1;
  1110.     }
  1111.  
  1112.     /*Make the origin*/
  1113.     textBox = TemplateTextBox(VisContoursTemplate, "Origin Text", 0, "Origin:");
  1114.     PrefixList(panelContents, textBox);
  1115.     SetVar(textBox, PARENT, panelContents);
  1116.  
  1117.     PrintNumber(number, origin); 
  1118.     textBox = TemplateTextBox(VisContoursTemplate, "Origin",
  1119.              EDITABLE + WITH_PIT + ONE_LINE, number);
  1120.     SetVar(textBox, PARENT, panelContents);
  1121.     PrefixList(panelContents, textBox);
  1122.     SetTextAlign(textBox, RIGHTALIGN);
  1123.     AssocTextRealControlWithVar(textBox, contour, CONTOURCENTER, minusInf, plusInf, TR_NE_BOTTOM | TR_NE_TOP);
  1124.     SetVar(textBox, HELPSTRING,
  1125.     NewString("This number specifies the origin of the contours.  \
  1126. Contours are calculated starting at the origin, increasing and decreasing by the steps \
  1127. specified in the major and minor contours parameters, until the minimum or maximum is reached.\
  1128. For most ordinary contours that cover the entire visualization range, this does not \
  1129. need to be changed."));
  1130.  
  1131.     /*Make the minimum*/
  1132.     textBox = TemplateTextBox(VisContoursTemplate, "Minimum Text", 
  1133.                 0, "Minimum:");
  1134.     PrefixList(panelContents, textBox);
  1135.     SetVar(textBox, PARENT, panelContents);
  1136.  
  1137.     PrintNumber(number, min); 
  1138.     textBox = TemplateTextBox(VisContoursTemplate, "Minimum",
  1139.              EDITABLE + WITH_PIT + ONE_LINE, number);
  1140.     SetVar(textBox, PARENT, panelContents);
  1141.     PrefixList(panelContents, textBox);
  1142.     SetTextAlign(textBox, RIGHTALIGN);
  1143.     AssocTextRealControlWithVar(textBox, contour, CONTOURMIN, minusInf, plusInf, TR_NE_BOTTOM);
  1144.     SetVar(textBox, HELPSTRING,
  1145.     NewString("This number specifies the minimum contour value.  \
  1146. Contours are calculated starting at the origin, increasing and decreasing by the steps \
  1147. specified in the major and minor contours parameters, until the minimum or maximum is reached.  \
  1148. For most ordinary contours that cover the entire visualization range, this does not \
  1149. need to be changed.\n"));
  1150.  
  1151.     /*Make the maximum*/
  1152.     textBox = TemplateTextBox(VisContoursTemplate, "Maximum Text", 0, "Maximum:");
  1153.     PrefixList(panelContents, textBox);
  1154.     SetVar(textBox, PARENT, panelContents);
  1155.  
  1156.     PrintNumber(number, max); 
  1157.     textBox = TemplateTextBox(VisContoursTemplate, "Maximum",
  1158.             EDITABLE + WITH_PIT + ONE_LINE, number);
  1159.     SetVar(textBox, PARENT, panelContents);
  1160.     PrefixList(panelContents, textBox);
  1161.     SetTextAlign(textBox, RIGHTALIGN);
  1162.     AssocTextRealControlWithVar(textBox, contour, CONTOURMAX, minusInf, plusInf, TR_NE_BOTTOM);
  1163.     SetVar(textBox, HELPSTRING,
  1164.     NewString("This number specifies the maximum contour value.  \
  1165. Contours are calculated starting at the origin, increasing and decreasing by the steps \
  1166. specified in the major and minor contours parameters, until the minimum or maximum is reached.  \
  1167. For most ordinary contours that cover the entire visualization range, this does not \
  1168. need to be changed.\n"));
  1169.  
  1170.     /*Make the major contour controls*/
  1171.     textBox = TemplateTextBox(VisContoursTemplate, "Step Text", 
  1172.              0, "Major Step:");
  1173.     PrefixList(panelContents, textBox);
  1174.     SetVar(textBox, PARENT, panelContents);
  1175.  
  1176.     PrintNumber(number, step); 
  1177.     textBox = TemplateTextBox(VisContoursTemplate, "Step", 
  1178.              EDITABLE + WITH_PIT + ONE_LINE, number);
  1179.     SetVar(textBox, PARENT, panelContents);
  1180.     PrefixList(panelContents, textBox);
  1181.     SetTextAlign(textBox, RIGHTALIGN);
  1182.     AssocTextRealControlWithVar(textBox, contour, CONTOURSTEP, 0.0, plusInf, TR_NE_BOTTOM | TR_NE_TOP);
  1183.     SetVar(textBox, HELPSTRING,
  1184.     NewString("This number specifies the step size of the major contours.  \
  1185. It must be a real number greater than 0.  \
  1186. Contours are calculated starting at the origin, increasing and decreasing by the steps \
  1187. specified in the major and minor contours parameters, until the minimum or maximum is reached."));
  1188.  
  1189.     /*Make the minor contour controls*/
  1190.     textBox = TemplateTextBox(VisContoursTemplate, "Divisions Text", 
  1191.              0, "Minor Divisions:");
  1192.     PrefixList(panelContents, textBox);
  1193.     SetVar(textBox, PARENT, panelContents);
  1194.  
  1195.     PrintNumber(number, (real) divisions); 
  1196.     textBox = TemplateTextBox(VisContoursTemplate, "Divisions", 
  1197.              EDITABLE + WITH_PIT + ONE_LINE, number);
  1198.     SetVar(textBox, PARENT, panelContents);
  1199.     PrefixList(panelContents, textBox);
  1200.     SetTextAlign(textBox, RIGHTALIGN);
  1201.     AssocTextIntControlWithVar(textBox, contour, CONTOURDIV, 1.0, plusInf, TR_INT_ONLY | TR_NE_TOP);
  1202.     SetVar(textBox, HELPSTRING,
  1203.     NewString("This text box contains a number giving the number of divisions between \
  1204. major contours.  \
  1205. This must be an integer greater than zero.  For example, a value of 1 gives no minor divisions \
  1206. between major contours.  A value of 10 gives one major contour every 10 divisions.  \
  1207. Contours are calculated starting at the origin, increasing and decreasing by the steps \
  1208. specified in the major and minor contours parameters, until the minimum or maximum is reached."));
  1209.  
  1210.     return ObjTrue;
  1211. }
  1212.  
  1213. ObjPtr MakeContourLines(contour)
  1214. ObjPtr contour;
  1215. /*Makes some contour lines*/
  1216. {
  1217.     ObjPtr line, lines;
  1218.     SetVar(contour, CONTOURLINES, lines = NewList());
  1219.  
  1220.     return ObjTrue;
  1221. }
  1222.  
  1223. void InitContours()
  1224. /*Initializes the contour objects*/
  1225. {
  1226.     ObjPtr icon, color;
  1227.  
  1228.     /*Class for a contour line*/
  1229.     contourLineClass = NewObject(NULLOBJ, 0);
  1230.     color = NewRealArray(1, 3L);
  1231.     ((real *) ELEMENTS(color))[0] = 1.0;
  1232.     ((real *) ELEMENTS(color))[1] = 1.0;
  1233.     ((real *) ELEMENTS(color))[2] = 1.0;
  1234.     SetVar(contourLineClass, BASECOLOR, color);
  1235.     AddToReferenceList(contourLineClass);
  1236.  
  1237.     /*Class for a contour object*/
  1238.     contoursClass = NewObject(visDeformed, 0);
  1239.     AddToReferenceList(contoursClass);
  1240.     SetVar(contoursClass, NAME, NewString("Contours"));
  1241.     SetMethod(contoursClass, INITIALIZE, ContoursInit);
  1242.     SetVar(contoursClass, SHINVAL, NewReal(80.0));
  1243.     SetVar(contoursClass, SPECVAL, NewReal(0.2));
  1244.     SetVar(contoursClass, DEFAULTICON, icon = NewObject(visIcon, 0));
  1245.     SetMethod(contoursClass, CONTOURLINES, MakeContourLines);
  1246.     SetVar(contoursClass, DRAWSURFACE, ObjFalse);
  1247.     SetVar(contoursClass, DRAWWIREFRAME, ObjTrue);
  1248.     SetVar(icon, WHICHICON, NewInt(ICONCONTOURS));
  1249.     SetVar(icon, NAME, NewString("Contours"));
  1250.     SetVar(icon, HELPSTRING,
  1251.     NewString("This icon represents a contour visualization object.  \
  1252. The contour object shows contours and shaded color surfaces of 2-dimensional \
  1253. scalar fields defined over structured or nonstructured grids."));
  1254.     DeclareIndirectDependency(contoursClass, SURFACE, MAINDATASET, CHANGED);
  1255.     DeclareDependency(contoursClass, SURFACE, COLORCELLS);
  1256.     SetMethod(contoursClass, SURFACE, MakeContoursSurface);
  1257.     DeclareDependency(contoursClass, SURFACE, REVERSESENSE);
  1258.     DeclareDependency(contoursClass, SURFACE, CONTOURCENTER);
  1259.     DeclareDependency(contoursClass, SURFACE, CONTOURSTEP);
  1260.     DeclareDependency(contoursClass, SURFACE, CONTOURMAX);
  1261.     DeclareDependency(contoursClass, SURFACE, CONTOURDIV);
  1262.     DeclareDependency(contoursClass, SURFACE, CONTOURMIN);
  1263.  
  1264.     SetMethod(contoursClass, PICCOLORED, MakeContoursColored);
  1265.     SetMethod(contoursClass, SETMAINDATASET, SetContoursMainDataset);
  1266.  
  1267.     SetMethod(contoursClass, ADDCONTROLS, AddContourControls);
  1268.     icon = NewIcon(0, 0, ICONCONTOURS, "Contours");
  1269.     SetVar(contoursClass, CONTROLICON, icon);
  1270.  
  1271.     DefineVisMapping(DS_HASFORM | DS_HASFIELD, 2, 3, 1, contoursClass);
  1272.     DefineVisMapping(DS_HASFORM | DS_HASFIELD, 2, 2, 1, contoursClass);
  1273.     DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_UNSTRUCTURED, 2, 3, 1, contoursClass);
  1274.     DefineVisMapping(DS_HASFORM | DS_HASFIELD | DS_UNSTRUCTURED, 2, 2, 1, contoursClass);
  1275. }
  1276.  
  1277. void KillContours()
  1278. /*Kills the contours*/
  1279. {
  1280.     DeleteThing(contoursClass);
  1281.     DeleteThing(contourLineClass);
  1282. }
  1283.